/**
 * 负载测试脚本
 * Load Testing Script
 */

const http = require('http');
const https = require('https');
const path = require('path');
const { Worker, isMainThread, parentPort, workerData } = require('worker_threads');
const os = require('os');

// 加载配置
require('dotenv').config({ path: path.join(__dirname, '../../.env') });

const config = {
  app: {
    baseUrl: process.env.BASE_URL || 'http://localhost:3000',
    timeout: 30000
  },
  test: {
    adminEmail: 'admin@test.com',
    adminPassword: 'TestAdmin123!',
    testUserEmail: 'loadtest@test.com',
    testUserPassword: 'LoadTest123!',
    testUserNickname: '负载测试用户'
  },
  load: {
    maxConcurrentUsers: 50,
    testDurationSeconds: 60,
    rampUpSeconds: 10,
    thinkTimeMs: 1000,
    maxResponseTimeMs: 5000,
    errorRateThreshold: 5 // 5%
  }
};

// 颜色定义
const colors = {
  reset: '\x1b[0m',
  red: '\x1b[31m',
  green: '\x1b[32m',
  yellow: '\x1b[33m',
  blue: '\x1b[34m',
  cyan: '\x1b[36m'
};

function printMessage(color, message) {
  console.log(`${color}${message}${colors.reset}`);
}

/**
 * HTTP请求工具函数
 */
function makeRequest(options, data = null) {
  return new Promise((resolve, reject) => {
    const protocol = options.protocol === 'https:' ? https : http;
    const startTime = Date.now();
    
    const req = protocol.request(options, (res) => {
      let responseData = '';
      
      res.on('data', (chunk) => {
        responseData += chunk;
      });
      
      res.on('end', () => {
        const endTime = Date.now();
        const responseTime = endTime - startTime;
        
        try {
          const parsedData = responseData ? JSON.parse(responseData) : {};
          resolve({
            statusCode: res.statusCode,
            headers: res.headers,
            data: parsedData,
            rawData: responseData,
            responseTime
          });
        } catch (error) {
          resolve({
            statusCode: res.statusCode,
            headers: res.headers,
            data: null,
            rawData: responseData,
            responseTime
          });
        }
      });
    });
    
    req.on('error', (error) => {
      const endTime = Date.now();
      reject({
        error: error.message,
        responseTime: endTime - startTime
      });
    });
    
    req.setTimeout(config.app.timeout, () => {
      req.destroy();
      const endTime = Date.now();
      reject({
        error: '请求超时',
        responseTime: endTime - startTime
      });
    });
    
    if (data) {
      req.write(typeof data === 'string' ? data : JSON.stringify(data));
    }
    req.end();
  });
}

function parseUrl(url) {
  const urlObj = new URL(url);
  return {
    protocol: urlObj.protocol,
    hostname: urlObj.hostname,
    port: urlObj.port || (urlObj.protocol === 'https:' ? 443 : 80),
    path: urlObj.pathname + urlObj.search
  };
}

/**
 * 虚拟用户类
 */
class VirtualUser {
  constructor(userId) {
    this.userId = userId;
    this.authToken = null;
    this.metrics = {
      requests: 0,
      errors: 0,
      responseTimes: [],
      actions: []
    };
  }

  /**
   * 记录请求结果
   */
  recordRequest(action, success, responseTime, error = null) {
    this.metrics.requests++;
    this.metrics.responseTimes.push(responseTime);
    this.metrics.actions.push({
      action,
      success,
      responseTime,
      error,
      timestamp: Date.now()
    });

    if (!success) {
      this.metrics.errors++;
    }
  }

  /**
   * 用户登录
   */
  async login() {
    try {
      const url = parseUrl(`${config.app.baseUrl}/api/auth/login`);
      const response = await makeRequest({
        ...url,
        method: 'POST',
        headers: { 'Content-Type': 'application/json' }
      }, {
        email: config.test.testUserEmail,
        password: config.test.testUserPassword
      });

      const success = response.statusCode === 200 && response.data.token;
      this.recordRequest('login', success, response.responseTime);

      if (success) {
        this.authToken = response.data.token;
      }

      return success;
    } catch (error) {
      this.recordRequest('login', false, error.responseTime, error.error);
      return false;
    }
  }

  /**
   * 获取笔记列表
   */
  async getNotesList() {
    if (!this.authToken) return false;

    try {
      const url = parseUrl(`${config.app.baseUrl}/api/notes?page=1&limit=10`);
      const response = await makeRequest({
        ...url,
        method: 'GET',
        headers: { 'Authorization': `Bearer ${this.authToken}` }
      });

      const success = response.statusCode === 200;
      this.recordRequest('getNotesList', success, response.responseTime);
      return success;
    } catch (error) {
      this.recordRequest('getNotesList', false, error.responseTime, error.error);
      return false;
    }
  }

  /**
   * 创建笔记
   */
  async createNote() {
    if (!this.authToken) return false;

    try {
      const url = parseUrl(`${config.app.baseUrl}/api/notes`);
      const response = await makeRequest({
        ...url,
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'Authorization': `Bearer ${this.authToken}`
        }
      }, {
        title: `负载测试笔记 - 用户${this.userId} - ${Date.now()}`,
        content: `<p>这是用户${this.userId}在负载测试中创建的笔记。</p><p>创建时间: ${new Date().toLocaleString()}</p>`
      });

      const success = response.statusCode === 200;
      this.recordRequest('createNote', success, response.responseTime);
      return success;
    } catch (error) {
      this.recordRequest('createNote', false, error.responseTime, error.error);
      return false;
    }
  }

  /**
   * 搜索笔记
   */
  async searchNotes() {
    if (!this.authToken) return false;

    try {
      const searchTerms = ['测试', '笔记', '负载', '用户'];
      const term = searchTerms[Math.floor(Math.random() * searchTerms.length)];
      
      const url = parseUrl(`${config.app.baseUrl}/api/notes/search?q=${encodeURIComponent(term)}`);
      const response = await makeRequest({
        ...url,
        method: 'GET',
        headers: { 'Authorization': `Bearer ${this.authToken}` }
      });

      const success = response.statusCode === 200;
      this.recordRequest('searchNotes', success, response.responseTime);
      return success;
    } catch (error) {
      this.recordRequest('searchNotes', false, error.responseTime, error.error);
      return false;
    }
  }

  /**
   * 获取文件列表
   */
  async getFilesList() {
    if (!this.authToken) return false;

    try {
      const url = parseUrl(`${config.app.baseUrl}/api/files?path=/`);
      const response = await makeRequest({
        ...url,
        method: 'GET',
        headers: { 'Authorization': `Bearer ${this.authToken}` }
      });

      const success = response.statusCode === 200;
      this.recordRequest('getFilesList', success, response.responseTime);
      return success;
    } catch (error) {
      this.recordRequest('getFilesList', false, error.responseTime, error.error);
      return false;
    }
  }

  /**
   * 获取用户信息
   */
  async getUserProfile() {
    if (!this.authToken) return false;

    try {
      const url = parseUrl(`${config.app.baseUrl}/api/user/profile`);
      const response = await makeRequest({
        ...url,
        method: 'GET',
        headers: { 'Authorization': `Bearer ${this.authToken}` }
      });

      const success = response.statusCode === 200;
      this.recordRequest('getUserProfile', success, response.responseTime);
      return success;
    } catch (error) {
      this.recordRequest('getUserProfile', false, error.responseTime, error.error);
      return false;
    }
  }

  /**
   * 执行用户场景
   */
  async runScenario() {
    // 登录
    const loginSuccess = await this.login();
    if (!loginSuccess) {
      return this.metrics;
    }

    // 模拟用户行为序列
    const actions = [
      () => this.getUserProfile(),
      () => this.getNotesList(),
      () => this.createNote(),
      () => this.searchNotes(),
      () => this.getFilesList(),
      () => this.getNotesList() // 再次获取列表查看新创建的笔记
    ];

    for (const action of actions) {
      await action();
      
      // 模拟用户思考时间
      if (config.load.thinkTimeMs > 0) {
        await new Promise(resolve => setTimeout(resolve, config.load.thinkTimeMs));
      }
    }

    return this.metrics;
  }
}

/**
 * 负载测试工作线程
 */
async function workerThread() {
  const { workerId, userCount, duration } = workerData;
  const users = [];
  const results = [];

  // 创建虚拟用户
  for (let i = 0; i < userCount; i++) {
    users.push(new VirtualUser(`${workerId}-${i}`));
  }

  const startTime = Date.now();
  const endTime = startTime + (duration * 1000);

  // 并发执行用户场景
  const userPromises = users.map(async (user) => {
    while (Date.now() < endTime) {
      const metrics = await user.runScenario();
      
      // 随机等待一段时间再开始下一轮
      const waitTime = Math.random() * 2000 + 1000; // 1-3秒
      await new Promise(resolve => setTimeout(resolve, waitTime));
    }
    
    return user.metrics;
  });

  const userResults = await Promise.all(userPromises);
  
  // 汇总结果
  const summary = {
    workerId,
    userCount,
    totalRequests: 0,
    totalErrors: 0,
    responseTimes: [],
    actionStats: {}
  };

  userResults.forEach(metrics => {
    summary.totalRequests += metrics.requests;
    summary.totalErrors += metrics.errors;
    summary.responseTimes.push(...metrics.responseTimes);
    
    metrics.actions.forEach(action => {
      if (!summary.actionStats[action.action]) {
        summary.actionStats[action.action] = {
          count: 0,
          errors: 0,
          responseTimes: []
        };
      }
      
      summary.actionStats[action.action].count++;
      summary.actionStats[action.action].responseTimes.push(action.responseTime);
      
      if (!action.success) {
        summary.actionStats[action.action].errors++;
      }
    });
  });

  parentPort.postMessage(summary);
}

/**
 * 负载测试管理器
 */
class LoadTestManager {
  constructor() {
    this.results = [];
    this.adminToken = null;
  }

  /**
   * 准备测试环境
   */
  async prepareTestEnvironment() {
    printMessage(colors.blue, '准备测试环境...');

    // 管理员登录
    const loginUrl = parseUrl(`${config.app.baseUrl}/api/auth/login`);
    const loginResponse = await makeRequest({
      ...loginUrl,
      method: 'POST',
      headers: { 'Content-Type': 'application/json' }
    }, {
      email: config.test.adminEmail,
      password: config.test.adminPassword
    });

    if (loginResponse.statusCode !== 200 || !loginResponse.data.token) {
      throw new Error('管理员登录失败');
    }

    this.adminToken = loginResponse.data.token;

    // 创建或确保测试用户存在
    const createUserUrl = parseUrl(`${config.app.baseUrl}/api/admin/users`);
    const createResponse = await makeRequest({
      ...createUserUrl,
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'Authorization': `Bearer ${this.adminToken}`
      }
    }, {
      email: config.test.testUserEmail,
      password: config.test.testUserPassword,
      nickname: config.test.testUserNickname
    });

    // 如果用户已存在，不算错误
    if (createResponse.statusCode !== 200 && createResponse.statusCode !== 409) {
      throw new Error('创建测试用户失败');
    }

    printMessage(colors.green, '测试环境准备完成');
  }

  /**
   * 运行负载测试
   */
  async runLoadTest() {
    const workerCount = Math.min(os.cpus().length, 4); // 限制工作线程数量
    const usersPerWorker = Math.ceil(config.load.maxConcurrentUsers / workerCount);
    
    printMessage(colors.blue, `启动负载测试:`);
    printMessage(colors.blue, `  并发用户数: ${config.load.maxConcurrentUsers}`);
    printMessage(colors.blue, `  测试持续时间: ${config.load.testDurationSeconds}秒`);
    printMessage(colors.blue, `  工作线程数: ${workerCount}`);
    printMessage(colors.blue, `  每线程用户数: ${usersPerWorker}`);
    console.log();

    const workers = [];
    const workerPromises = [];

    // 创建工作线程
    for (let i = 0; i < workerCount; i++) {
      const worker = new Worker(__filename, {
        workerData: {
          workerId: i,
          userCount: usersPerWorker,
          duration: config.load.testDurationSeconds
        }
      });

      workers.push(worker);

      const workerPromise = new Promise((resolve, reject) => {
        worker.on('message', (result) => {
          this.results.push(result);
          resolve(result);
        });

        worker.on('error', reject);
        worker.on('exit', (code) => {
          if (code !== 0) {
            reject(new Error(`工作线程 ${i} 异常退出，代码: ${code}`));
          }
        });
      });

      workerPromises.push(workerPromise);
    }

    // 显示进度
    const progressInterval = setInterval(() => {
      const elapsed = Math.floor((Date.now() - Date.now()) / 1000);
      const remaining = Math.max(0, config.load.testDurationSeconds - elapsed);
      process.stdout.write(`\r测试进行中... 剩余时间: ${remaining}秒`);
    }, 1000);

    try {
      // 等待所有工作线程完成
      await Promise.all(workerPromises);
      clearInterval(progressInterval);
      console.log('\n');
      
      // 终止工作线程
      workers.forEach(worker => worker.terminate());
      
      printMessage(colors.green, '负载测试完成');
    } catch (error) {
      clearInterval(progressInterval);
      workers.forEach(worker => worker.terminate());
      throw error;
    }
  }

  /**
   * 分析测试结果
   */
  analyzeResults() {
    if (this.results.length === 0) {
      throw new Error('没有测试结果可分析');
    }

    const summary = {
      totalRequests: 0,
      totalErrors: 0,
      responseTimes: [],
      actionStats: {},
      workers: this.results.length
    };

    // 汇总所有工作线程的结果
    this.results.forEach(result => {
      summary.totalRequests += result.totalRequests;
      summary.totalErrors += result.totalErrors;
      summary.responseTimes.push(...result.responseTimes);

      Object.keys(result.actionStats).forEach(action => {
        if (!summary.actionStats[action]) {
          summary.actionStats[action] = {
            count: 0,
            errors: 0,
            responseTimes: []
          };
        }

        summary.actionStats[action].count += result.actionStats[action].count;
        summary.actionStats[action].errors += result.actionStats[action].errors;
        summary.actionStats[action].responseTimes.push(...result.actionStats[action].responseTimes);
      });
    });

    // 计算统计指标
    const stats = {
      totalRequests: summary.totalRequests,
      totalErrors: summary.totalErrors,
      errorRate: (summary.totalErrors / summary.totalRequests * 100).toFixed(2),
      avgResponseTime: (summary.responseTimes.reduce((a, b) => a + b, 0) / summary.responseTimes.length).toFixed(2),
      minResponseTime: Math.min(...summary.responseTimes),
      maxResponseTime: Math.max(...summary.responseTimes),
      p95ResponseTime: this.calculatePercentile(summary.responseTimes, 95),
      p99ResponseTime: this.calculatePercentile(summary.responseTimes, 99),
      requestsPerSecond: (summary.totalRequests / config.load.testDurationSeconds).toFixed(2),
      actionStats: {}
    };

    // 计算各个操作的统计
    Object.keys(summary.actionStats).forEach(action => {
      const actionData = summary.actionStats[action];
      stats.actionStats[action] = {
        count: actionData.count,
        errors: actionData.errors,
        errorRate: (actionData.errors / actionData.count * 100).toFixed(2),
        avgResponseTime: (actionData.responseTimes.reduce((a, b) => a + b, 0) / actionData.responseTimes.length).toFixed(2),
        p95ResponseTime: this.calculatePercentile(actionData.responseTimes, 95)
      };
    });

    return stats;
  }

  /**
   * 计算百分位数
   */
  calculatePercentile(values, percentile) {
    const sorted = values.slice().sort((a, b) => a - b);
    const index = Math.ceil((percentile / 100) * sorted.length) - 1;
    return sorted[index] || 0;
  }

  /**
   * 显示测试结果
   */
  displayResults(stats) {
    printMessage(colors.cyan, '负载测试结果');
    printMessage(colors.cyan, '================');
    console.log();

    printMessage(colors.blue, '总体统计:');
    console.log(`  总请求数: ${stats.totalRequests}`);
    console.log(`  总错误数: ${stats.totalErrors}`);
    console.log(`  错误率: ${stats.errorRate}%`);
    console.log(`  请求/秒: ${stats.requestsPerSecond}`);
    console.log();

    printMessage(colors.blue, '响应时间统计 (毫秒):');
    console.log(`  平均响应时间: ${stats.avgResponseTime}`);
    console.log(`  最小响应时间: ${stats.minResponseTime}`);
    console.log(`  最大响应时间: ${stats.maxResponseTime}`);
    console.log(`  95%响应时间: ${stats.p95ResponseTime}`);
    console.log(`  99%响应时间: ${stats.p99ResponseTime}`);
    console.log();

    printMessage(colors.blue, '操作统计:');
    Object.keys(stats.actionStats).forEach(action => {
      const actionStats = stats.actionStats[action];
      console.log(`  ${action}:`);
      console.log(`    请求数: ${actionStats.count}`);
      console.log(`    错误数: ${actionStats.errors} (${actionStats.errorRate}%)`);
      console.log(`    平均响应时间: ${actionStats.avgResponseTime}ms`);
      console.log(`    95%响应时间: ${actionStats.p95ResponseTime}ms`);
    });
    console.log();

    // 性能评估
    this.evaluatePerformance(stats);
  }

  /**
   * 评估性能
   */
  evaluatePerformance(stats) {
    printMessage(colors.blue, '性能评估:');
    
    const issues = [];
    const warnings = [];

    // 错误率检查
    if (parseFloat(stats.errorRate) > config.load.errorRateThreshold) {
      issues.push(`错误率过高: ${stats.errorRate}% (阈值: ${config.load.errorRateThreshold}%)`);
    }

    // 响应时间检查
    if (parseFloat(stats.avgResponseTime) > config.load.maxResponseTimeMs) {
      issues.push(`平均响应时间过长: ${stats.avgResponseTime}ms (阈值: ${config.load.maxResponseTimeMs}ms)`);
    }

    if (stats.p95ResponseTime > config.load.maxResponseTimeMs * 2) {
      warnings.push(`95%响应时间较长: ${stats.p95ResponseTime}ms`);
    }

    // 显示评估结果
    if (issues.length === 0 && warnings.length === 0) {
      printMessage(colors.green, '✓ 性能表现良好，所有指标都在可接受范围内');
    } else {
      if (issues.length > 0) {
        printMessage(colors.red, '严重性能问题:');
        issues.forEach(issue => {
          printMessage(colors.red, `  ✗ ${issue}`);
        });
      }

      if (warnings.length > 0) {
        printMessage(colors.yellow, '性能警告:');
        warnings.forEach(warning => {
          printMessage(colors.yellow, `  ⚠ ${warning}`);
        });
      }
    }
  }

  /**
   * 清理测试环境
   */
  async cleanupTestEnvironment() {
    if (!this.adminToken) return;

    try {
      // 删除测试用户
      const deleteUrl = parseUrl(`${config.app.baseUrl}/api/admin/users`);
      await makeRequest({
        ...deleteUrl,
        method: 'DELETE',
        headers: {
          'Content-Type': 'application/json',
          'Authorization': `Bearer ${this.adminToken}`
        }
      }, { email: config.test.testUserEmail });

      printMessage(colors.blue, '测试环境清理完成');
    } catch (error) {
      console.warn('清理测试环境时发生错误:', error.message);
    }
  }
}

/**
 * 主函数
 */
async function main() {
  if (!isMainThread) {
    // 工作线程执行
    await workerThread();
    return;
  }

  printMessage(colors.cyan, '个人云笔记负载测试');
  printMessage(colors.cyan, '====================');
  console.log();

  const loadTest = new LoadTestManager();

  try {
    // 准备测试环境
    await loadTest.prepareTestEnvironment();

    // 运行负载测试
    await loadTest.runLoadTest();

    // 分析和显示结果
    const stats = loadTest.analyzeResults();
    loadTest.displayResults(stats);

    // 根据结果决定退出码
    const success = parseFloat(stats.errorRate) <= config.load.errorRateThreshold && 
                   parseFloat(stats.avgResponseTime) <= config.load.maxResponseTimeMs;

    process.exit(success ? 0 : 1);

  } catch (error) {
    printMessage(colors.red, `负载测试失败: ${error.message}`);
    process.exit(1);
  } finally {
    // 清理测试环境
    await loadTest.cleanupTestEnvironment();
  }
}

// 错误处理
process.on('unhandledRejection', (error) => {
  printMessage(colors.red, `未处理的错误: ${error.message}`);
  process.exit(1);
});

// 运行主函数
if (require.main === module) {
  main().catch((error) => {
    printMessage(colors.red, `负载测试启动失败: ${error.message}`);
    process.exit(1);
  });
}

module.exports = {
  VirtualUser,
  LoadTestManager
};